package com.gss.plugin.oauth2.resource;

import com.gss.plugin.oauth2.config.Oauth2Properties;
import com.gss.plugin.oauth2.exception.ResourceAccessDeniedHandler;
import com.gss.plugin.oauth2.exception.ResourcePointHandler;
import com.gss.plugin.oauth2.filter.JWTAuthenticationFilter;
import com.gss.plugin.oauth2.handler.CustomAuth403Handler;
import com.gss.plugin.oauth2.handler.CustomAuthFilterExpressionHandler;
import com.gss.plugin.oauth2.service.ICustomAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import java.util.List;

/**
 * @author DYang
 * @date 2023/8/20
 * 资源服务器配置
 */
@ConditionalOnProperty(name = "stars.oauth-token.resource",havingValue = "true")
@Configuration
@EnableResourceServer   // 开启资源服务配置
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private Oauth2Properties oauth2Properties;
    @Autowired
    private CustomAuth403Handler customAuth403Handler;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;
    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;
    @Autowired
    private ICustomAuthService customAuthService;
    @Autowired
    private AuthenticationManager authenticationManager;


    /**
     * 配置access_token 远程验证策略
     * @return
     */
    @Bean
    public ResourceServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        //配置令牌存储策略，使用AccessTokenConfig配置JwtTokenStore
        services.setTokenStore(tokenStore);
        //令牌增强JwtAccessTokenConverter
        services.setTokenEnhancer(accessTokenConverter);
        return services;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources
                //资源id
                .resourceId(oauth2Properties.getResourceIds())
                //配置令牌校验服务
                .tokenServices(this.tokenServices())
                //token异常处理
                .authenticationEntryPoint(new ResourcePointHandler())
                //权限不足异常处理
                .accessDeniedHandler(new ResourceAccessDeniedHandler())
                //无状态模式，不需要验证用户session
                .stateless(true)
                //自定义认证策略
                .expressionHandler(new CustomAuthFilterExpressionHandler(customAuthService));
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 关闭csrf 防护
        http
                .cors()
            .and()
                .csrf().disable()
                .formLogin().permitAll()
                .and().logout().permitAll()
                // 单点登录
                //.and().logout().permitAll()
            .and()
                // 设置认证白名单，不需要认证的页面和接口
                .authorizeRequests().antMatchers(this.getWhiteList()).permitAll()
                // 其他认证方式
                .and().authorizeRequests().anyRequest().access("#customAuthService.hasPermission(request,authentication)")
            .and()
//                .addFilter(new JWTAuthenticationFilter(oauth2Properties,authenticationManager))
                .exceptionHandling()
                // 认证失败处理
                .accessDeniedHandler(customAuth403Handler);

        // 记住我功能
        if (oauth2Properties.isRememberMe()) {
            http.rememberMe()
                    // 记住我失效时间(s),默认2周
                    .tokenValiditySeconds(oauth2Properties.getRememberMeTime())
                    // 自定义登录逻辑
                    .userDetailsService(userDetailsService)
                    // 持久层对象
                    .tokenRepository(persistentTokenRepository);
        }

    }

    /**
     * 允许所有人访问的白名单列表
     * @return
     */
    private String[] getWhiteList() {
        List<String> whitelist = oauth2Properties.getAuthWhitelist();
        if (whitelist == null || whitelist.size() == 0) {
            return null;
        }
        String[] arr = new String[whitelist.size()];
        whitelist.toArray(arr);
        return arr;
    }


}
